﻿using System;
using System.Drawing;

namespace PO_2011.Filter
{
    public class Binarization : BitmapFastPixel
    {
        public static Bitmap GlobalBinarization(Bitmap inputImage, int threshold)
        {
            old_img = inputImage;
            int[] pColors;
            
            for (int y = 0; y < inputImage.Height; y++)
            {
                for (int x = 0; x < inputImage.Width; x++)
                {
                    pColors = getFastPixel(x, y);
                    if (pColors[0] < threshold || pColors[1] < threshold || pColors[2] < threshold)
                        setFastPixel(x, y, 0, 0, 0);
                    else setFastPixel(x, y, 255, 255, 255);
                }
            }

            return getNewImage(true);
        }

        public static int OtsuThresholding(Bitmap inputImage)
        {
            int threshold = 0;
            int[] hist = Histogram.CalcMonoHistogram(inputImage, 256);

            double varOb = 0;
            for (int i = 1; i < 255; i++)
            {
                double sumB = 0, varB = 0, meanB = 0, pCount = 0;

                for (int j = i + 1; j < 256; j++)
                {
                    pCount += hist[j];
                    sumB += hist[j] * j;
                }
                meanB = sumB / pCount;

                for (int j = i + 1; j < 256; j++)
                {
                    varB += Math.Pow(hist[j] - meanB, 2);
                }

                varB = varB / pCount;
                if (varB > varOb)
                {
                    varOb = varB;
                    threshold = i;
                }
            }
            
            return threshold;
        }

        public static Bitmap WhiteRohrerThresholding(Bitmap inputImage, int windowSize, float param)
        {
            old_img = inputImage;
            int[] pColors;

            for (int y = 0; y < inputImage.Height; y++)
            {
                for (int x = 0; x < inputImage.Width; x++)
                {
                    if (x <= windowSize / 2 || x > inputImage.Width - windowSize / 2 - 1 || y <= windowSize / 2 || y > inputImage.Height - windowSize / 2 - 1)
                    {
                        setFastPixel(x, y, 255, 255, 255);
                    }
                    else
                    {
                        int localX = x - windowSize / 2;
                        int localY = y - windowSize / 2;
                        int sumR = 0, sumG = 0, sumB = 0;

                        for (int m = 0; m < windowSize; m++)
                        {
                            for (int n = 0; n < windowSize; n++)
                            {
                                pColors = getFastPixel(localX, localY);
                                sumR += pColors[0];
                                sumG += pColors[1];
                                sumB += pColors[2];
                                localX++;
                            }
                            localY++;
                            localX = x - windowSize / 2;
                        }

                        int windowCount = windowSize * windowSize;
                        int threshold = (int)(((sumR / windowCount + sumG / windowCount + sumB / windowCount) / 3) / param);

                        pColors = getFastPixel(x, y);
                        if (pColors[0] < threshold || pColors[1] < threshold || pColors[2] < threshold)
                            setFastPixel(x, y, 0, 0, 0);
                        else setFastPixel(x, y, 255, 255, 255);
                    }
                }
            }

            return getNewImage(true);
        }

        public static Bitmap BernsenThresholding(Bitmap inputImage, int windowSize, float param)
        {
            old_img = inputImage;
            int[] pColors;

            for (int y = 0; y < inputImage.Height; y++)
            {
                for (int x = 0; x < inputImage.Width; x++)
                {
                    if (x <= windowSize / 2 || x > inputImage.Width - windowSize / 2 - 1 || y <= windowSize / 2 || y > inputImage.Height - windowSize / 2 - 1)
                    {
                        setFastPixel(x, y, 255, 255, 255);
                    }
                    else
                    {
                        int localX = x - windowSize / 2; 
                        int localY = y - windowSize / 2;
                        int maxR = 0, maxG = 0, maxB = 0, minR = 255, minG = 255, minB = 255;
                        for (int m = 0; m < windowSize; m++)
                        {
                            for (int n = 0; n < windowSize; n++)
                            {
                                pColors = getFastPixel(localX, localY);
                                minR = Math.Min(minR, pColors[0]);
                                minG = Math.Min(minG, pColors[1]);
                                minB = Math.Min(minB, pColors[2]);
                                maxR = Math.Min(maxR, pColors[0]);
                                maxG = Math.Min(maxG, pColors[1]);
                                maxB = Math.Min(maxB, pColors[2]);
                                localX++;
                            }
                            localY++;
                            localX = x - windowSize / 2;
                        }

                        float iMin = (minR + minG + minB) / 3;
                        float iMax = (maxR + maxG + maxB) / 3;

                        int threshold;
                        if (iMax - iMin <= param) threshold = 100;
                        else threshold = (int)((iMin + iMax) / 2);

                        pColors = getFastPixel(x, y);
                        if (pColors[0] < threshold || pColors[1] < threshold || pColors[2] < threshold)
                            setFastPixel(x, y, 0, 0, 0);
                        else setFastPixel(x, y, 255, 255, 255);
                    }
                }
            }

            return getNewImage(true);
        }

        public static Bitmap NilbackThresholding(Bitmap inputImage, int windowSize, float param)
        {
            old_img = inputImage;
            int[] pColors;

            for (int y = 0; y < inputImage.Height; y++)
            {
                for (int x = 0; x < inputImage.Width; x++)
                {
                    if (x <= windowSize / 2 || x > inputImage.Width - windowSize / 2 - 1 || y <= windowSize / 2 || y > inputImage.Height - windowSize / 2 - 1)
                    {
                        setFastPixel(x, y, 255, 255, 255);
                    }
                    else
                    {
                        int localX = x - windowSize / 2;
                        int localY = y - windowSize / 2;
                        int sumR = 0, sumG = 0, sumB = 0;

                        for (int m = 0; m < windowSize; m++)
                        {
                            for (int n = 0; n < windowSize; n++)
                            {
                                pColors = getFastPixel(localX, localY);
                                sumR += pColors[0];
                                sumG += pColors[1];
                                sumB += pColors[2];
                                localX++;
                            }
                            localY++;
                            localX = x - windowSize / 2;
                        }

                        int windowCount = windowSize * windowSize;
                        sumR /= windowCount;
                        sumG /= windowCount;
                        sumB /= windowCount;

                        localX = x - windowSize / 2;
                        localY = y - windowSize / 2;
                        int varR = 0, varG = 0, varB = 0;

                        for (int m = 0; m < windowSize; m++)
                        {
                            for (int n = 0; n < windowSize; n++)
                            {
                                pColors = getFastPixel(localX, localY);
                                varR += (pColors[0] - sumR) * (pColors[0] - sumR);
                                varG += (pColors[1] - sumG) * (pColors[1] - sumG);
                                varB += (pColors[2] - sumB) * (pColors[2] - sumB);
                                localX++;
                            }
                            localY++;
                            localX = x - windowSize / 2;
                        }

                        int threshold = (int)(((sumR + sumG + sumB) / 3 + (Math.Sqrt(varR / windowCount) + Math.Sqrt(varG / windowCount) + Math.Sqrt(varB / windowCount)) / 3) / 2);

                        pColors = getFastPixel(x, y);
                        if (pColors[0] < threshold || pColors[1] < threshold || pColors[2] < threshold)
                            setFastPixel(x, y, 0, 0, 0);
                        else setFastPixel(x, y, 255, 255, 255);
                    }
                }
            }

            return getNewImage(true);
        }

    }
}
